package top.lixunda.ecommerce.server.business;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import top.lixunda.commerce.common.core.entity.MessageObject;
import top.lixunda.commerce.common.core.exception.AppException;
import top.lixunda.commerce.common.core.proxy.HttpSessionProxy;
import top.lixunda.commerce.common.core.utils.ImageCodeUtil;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.common.utils.StringUtils;
import top.lixunda.ecommerce.server.auth.api.entity.cache.CacheAuthCode;
import top.lixunda.ecommerce.server.auth.api.entity.dto.EmailGeneralCodeDTO;
import top.lixunda.ecommerce.server.auth.api.feign.IFeignEmailAuthCode;
import top.lixunda.ecommerce.server.auth.api.feign.IFeignPhoneAuthCode;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.BusinessKeyConstants;
import top.lixunda.ecommerce.server.business.api.entity.InsertInfo;
import top.lixunda.ecommerce.server.business.api.entity.QiNiuCallbackBody;
import top.lixunda.ecommerce.server.business.api.entity.cache.*;
import top.lixunda.ecommerce.server.business.api.entity.dto.QiNiuFileDatabaseObjectDTO;
import top.lixunda.ecommerce.server.business.api.entity.vo.ImageUploadTokenVO;
import top.lixunda.ecommerce.server.business.utils.AccountControllerUtil;
import top.lixunda.ecommerce.server.user.api.entity.db.UserDetailDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.SendAuthCodeDTO;
import top.lixunda.ecommerce.server.user.api.entity.db.BindingTypeDO;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author Xumda
 * @version time:2019/11/26 14:20
 * <p>
 * controller层和service层共有的一些方法
 */
@SuppressWarnings({"WeakerAccess", "unused", "SpringJavaInjectionPointsAutowiringInspection", "deprecation", "SpringJavaAutowiredMembersInspection"})
@Slf4j
public class Base {

    private static final String NULL_STRING = "null";

    private static final Boolean NO_LOGIN = false;

    @Autowired
    private HttpSession httpSession;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private HttpServletResponse httpServletResponse;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private IFeignEmailAuthCode feignEmailAuthCode;

    @Autowired
    private IFeignPhoneAuthCode feignPhoneAuthCode;

    @Autowired
    private ObjectMapper objectMapper;

    private ImageCodeUtil imageCodeUtil = new ImageCodeUtil();

    private volatile HttpSessionProxy httpSessionProxy;

    /**
     * 验证码发送间隔
     */
    private static final int CODE_GAP = 56;

    @SuppressWarnings("SpellCheckingInspection")
    private static final String ACCESS_KEY = "K0-mYOpGusytx_JLH2X2zE2wzfOVVhxJttOsdy_j";

    @SuppressWarnings("SpellCheckingInspection")
    private static final String SECRET_KEY = "gVYUQkVaFOHWX-vmHdonxfzkZl6MWIlsgZdTEgVh";

    @SuppressWarnings("SpellCheckingInspection")
    private static final String BUCKET = "xumda-commerce";

    /**
     * 创建上传文件凭证
     *
     * @return 凭证
     */
    public ImageUploadTokenVO createUploadToken(String userId, String callbackUrl, String fileName) {
        return createUploadToken(userId, callbackUrl, fileName, 3600);
    }

    /**
     * 创建上传文件凭证
     *
     * @return 凭证
     */
    @SuppressWarnings("SpellCheckingInspection")
    public ImageUploadTokenVO createUploadToken(String userId, String callbackUrl, String fileName, long expireSeconds) {
        ImageUploadTokenVO dto = new ImageUploadTokenVO();
        dto.setCreateTime(LocalDateTime.now());
        Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
        StringMap putPolicy = new StringMap();
        putPolicy.put("callbackUrl", callbackUrl);
        putPolicy.put("callbackBody", "{" +
                "\"userId\":\"" + userId + "\"," +
                "\"key\":\"$(key)\"," +
                "\"bucket\":\"$(bucket)\"," +
                "\"hash\":\"$(etag)\"," +
                "\"fname\":\"$(fname)\"," +
                "\"fsize\":\"$(fsize)\"," +
                "\"mimeType\":\"$(mimeType)\"," +
                "\"ext\":\"$(ext)\"," +
                "\"fprefix\":\"$(fprefix)\"," +
                "\"hash\":\"$(hash)\"," +
                "\"param1\":\"$(x:param1)\"," +
                "\"param2\":\"$(x:param2)\"," +
                "\"param2\":$(x:param3)" +
                "}");
        putPolicy.put("callbackBodyType", "application/json");
        String upToken = auth.uploadToken(BUCKET, fileName, expireSeconds, putPolicy);
        System.out.println(upToken);

        dto.setToken(upToken);
        dto.setCallbackUrl(callbackUrl);
        dto.setFileName(fileName);
        dto.setExpireSeconds(expireSeconds);
        return dto;
    }

    public QiNiuCallbackBody uploadQiNiuFile(InputStream inputStream, String name) {
        return uploadQiNiuFile(inputStream, "", "", name);
    }

    public QiNiuCallbackBody uploadQiNiuFile(InputStream inputStream, String userId, String name) {
        return uploadQiNiuFile(inputStream, userId, "", name);
    }

    public QiNiuCallbackBody uploadQiNiuFile(InputStream inputStream, String userId, String userType, String name) {
        if (userId == null) {
            userId = "";
        }
        if (userType == null) {
            userType = "";
        }
        if (ObjectValidators.isEmpty(name)) {
            throw getAppException("文件名不能为空");
        }

        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.region2());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        StringMap putPolicy = new StringMap();
        putPolicy.put("returnBody", "{" +
                "\"userId\":\"" + userId + "\"," +
                "\"userType\":\"" + userType + "\"," +
                "\"key\":\"$(key)\"," +
                "\"bucket\":\"$(bucket)\"," +
                "\"hash\":\"$(etag)\"," +
                "\"fname\":\"$(fname)\"," +
                "\"fsize\":\"$(fsize)\"," +
                "\"mimeType\":\"$(mimeType)\"," +
                "\"ext\":\"$(ext)\"," +
                "\"fprefix\":\"$(fprefix)\"," +
                "\"hash\":\"$(hash)\"," +
                "\"param1\":\"$(x:param1)\"," +
                "\"param2\":\"$(x:param2)\"," +
                "\"param2\":$(x:param3)" +
                "}");
        putPolicy.put("callbackBodyType", "application/json");
        Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
        String upToken = auth.uploadToken(BUCKET, null, 3600, putPolicy);
        try {
            Response response = uploadManager.put(inputStream, name, upToken, null, null);
            //解析上传成功的结果
            return new Gson().fromJson(response.bodyString(), QiNiuCallbackBody.class);
        } catch (QiniuException ex) {
            Response r = ex.response;
            log.error(r.toString());
            try {
                log.error(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
            throw getAppException("保存文件失败");
        }
    }

    /**
     * 将 QiNiuCallbackBody 转换为 QiNiuFileDatabaseObjectDTO
     *
     * @param qiNiuCallbackBody 七牛云返回数据
     * @param userId            用户id
     * @param userType          用户类型
     * @return QiNiuFileDatabaseObjectDTO
     */
    public QiNiuFileDatabaseObjectDTO createQiNiuDo(QiNiuCallbackBody qiNiuCallbackBody, Integer userId, String userType) {
        QiNiuFileDatabaseObjectDTO qiNiuFileDO = new QiNiuFileDatabaseObjectDTO();
        BeanUtils.copyProperties(qiNiuCallbackBody, qiNiuFileDO);
        qiNiuFileDO.setFileKey(qiNiuCallbackBody.getKey());
        if (NULL_STRING.equals(qiNiuFileDO.getParam1())) {
            qiNiuFileDO.setParam1(null);
        }
        if (NULL_STRING.equals(qiNiuFileDO.getParam2())) {
            qiNiuFileDO.setParam2(null);
        }
        if (NULL_STRING.equals(qiNiuFileDO.getParam3())) {
            qiNiuFileDO.setParam3(null);
        }
        qiNiuFileDO.setCreateTime(LocalDateTime.now())
                .setUserId(userId)
                .setUserType(userType);
        return qiNiuFileDO;
    }

    /**
     * 获取HttpSessionProxy，使用懒加载防止httpSession注入失败
     *
     * @return HttpSessionProxy
     */
    public HttpSessionProxy getHttpSessionProxy() {
        if (httpSessionProxy == null) {
            synchronized (Base.class) {
                if (httpSessionProxy == null) {
                    if (httpSession == null) {
                        throw new AppException("错误， Base类中注入HttpSession失败");
                    }
                    httpSessionProxy = new HttpSessionProxy(httpSession, httpServletRequest);
                }
            }
        }
        return this.httpSessionProxy;
    }

    /**
     * 缓存店铺信息
     *
     * @param cacheStore 店铺信息缓存
     */
    public void saveStoreCache(CacheStore cacheStore) {
        if (ObjectValidators.isEmpty(cacheStore)) {
            throw new AppException("缓存数据storeCache不能为空");
        }
        getHttpSessionProxy().setAttribute(BusinessKeyConstants.SESSION_CACHE_STORE, cacheStore);
    }

    /**
     * 缓存店铺用户信息
     *
     * @param cacheStoreUser 店铺信息用户信息
     */
    public void saveStoreUserCache(CacheStoreUser cacheStoreUser) {
        if (ObjectValidators.isEmpty(cacheStoreUser)) {
            throw new AppException("缓存数据cacheStoreUser不能为空");
        }
        getHttpSessionProxy().setAttribute(BusinessKeyConstants.SESSION_CACHE_STORE_USER, cacheStoreUser);
    }

    /**
     * 缓存普通用户登陆
     *
     * @param cacheUser 缓存信息
     */
    public void saveUserCache(CacheUser cacheUser) {
        if (ObjectValidators.isEmpty(cacheUser)) {
            throw new AppException("缓存数据cacheUser不能为空");
        }
        getHttpSessionProxy().setAttribute(BusinessKeyConstants.SESSION_CACHE_USER, cacheUser);
    }

    /**
     * 缓存管理员用户登陆
     *
     * @param cacheAdminUser 缓存信息
     */
    public void saveAdminUserCache(CacheAdminUser cacheAdminUser) {
        if (ObjectValidators.isEmpty(cacheAdminUser)) {
            throw new AppException("缓存数据cacheAdminUser不能为空");
        }
        getHttpSessionProxy().setAttribute(BusinessKeyConstants.SESSION_CACHE_ADMIN_USER, cacheAdminUser);
    }

    /**
     * 缓存普通用户登陆
     *
     * @param cacheLoginUser 缓存信息
     */
    public void saveLoginUserCache(CacheLoginUser cacheLoginUser) {
        if (ObjectValidators.isEmpty(cacheLoginUser)) {
            throw new AppException("缓存数据cacheLoginUserInfo不能为空");
        }
        getHttpSessionProxy().setAttribute(BusinessKeyConstants.SESSION_CACHE_LOGIN_USER, cacheLoginUser);
    }

    /**
     * 获取InsertInfo
     *
     * @return InsertInfo
     */
    public InsertInfo getInsertInfo() {
        InsertInfo insertInfo = new InsertInfo();
        LocalDateTime time = LocalDateTime.now();
        insertInfo.setTime(time)
                .setCreateTime(time)
                .setUpdateTime(time);
        return insertInfo;
    }

    /**
     * token自动登录，token来源于header
     *
     * @return 是否成功登录
     */
    private UserDetailDO autoLoginByToken() {
        String token = request.getHeader("Authorization");
        if (ObjectValidators.isEmpty(token)) {
            return null;
        }
        MessageObject<UserDetailDO> response = AccountControllerUtil.loginByTokenString(token);
        if (ObjectValidators.isEmpty(response)) {
            log.info("自动登录返回结果为空：token = " + token);
            return null;
        }
        if (response.isNotSuccess()) {
            log.info("自动登录失败：token = {} code = {} message = ", token, response.getCode(), response.getMsg());
            return null;
        }
        UserDetailDO userDetailDO = response.getObject();
        if (ObjectValidators.isEmpty(userDetailDO)) {
            log.info("自动登录返回结果为空：token = {}", token);
            return null;
        }
        // 保存结果
        try {
            httpServletResponse.setHeader("AUTO_LOGIN_INFO", objectMapper.writeValueAsString(userDetailDO));
        } catch (JsonProcessingException e) {
            log.info("自动登录UserDetailDO转Json失败：userDetailDO = {}  message = {}", userDetailDO.toString(), e.getMessage());
            return null;
        }
        httpServletResponse.setHeader("AUTO_LOGIN", "true");
        return userDetailDO;
    }

    /**
     * 获取店铺缓存数据
     *
     * @return 店铺缓存数据
     */
    public CacheStore currentStoreCache() {
        CacheStore cacheStore;
        if (NO_LOGIN) {
            cacheStore = new CacheStore();
            cacheStore.setId(10000);
            cacheStore.setName("星星之火");
        } else {
            cacheStore = this.getHttpSessionProxy()
                    .getAttribute(BusinessKeyConstants.SESSION_CACHE_STORE, CacheStore.class);
        }
        if (ObjectValidators.isEmpty(cacheStore)) {
            UserDetailDO success = autoLoginByToken();
            if (ObjectValidators.isNotEmpty(success)) {
                cacheStore = this.getHttpSessionProxy()
                        .getAttribute(BusinessKeyConstants.SESSION_CACHE_STORE, CacheStore.class);
            }
        }
        return cacheStore;
    }

    /**
     * 获取绝对不为空的店铺缓存数据，为空时抛出异常
     *
     * @return 店铺缓存数据
     */
    public CacheStore currentStoreCacheNotNull() {
        CacheStore cache = currentStoreCache();
        if (ObjectValidators.isEmpty(cache)) {
            if (ObjectValidators.isEmpty(currentLoginUserCache())) {
                throw getAppException(MessageObject.CODE_NOT_LOGIN, "未登录，请登录后重试！");
            } else {
                throw getAppException(MessageObject.CODE_DENY_ACCESS, "权限不足，需要店铺权限！");
            }
        }
        return cache;
    }

    /**
     * 获取用户信息缓存
     *
     * @return UserInfoDO
     */
    public CacheUser currentUserCache() {
        CacheUser cacheUser;
        if (NO_LOGIN) {
            cacheUser = new CacheUser();
            cacheUser.setAccount(10000);
            cacheUser.setName("李迅达");
            cacheUser.setFirstName("李");
            cacheUser.setLastName("迅达");
            cacheUser.setType(BusinessConstants.USER_TYPE_USER);
        } else {
            cacheUser = this.getHttpSessionProxy()
                    .getAttribute(BusinessKeyConstants.SESSION_CACHE_USER, CacheUser.class);
        }
        if (ObjectValidators.isEmpty(cacheUser)) {
            UserDetailDO success = autoLoginByToken();
            if (ObjectValidators.isNotEmpty(success)) {
                cacheUser = this.getHttpSessionProxy()
                        .getAttribute(BusinessKeyConstants.SESSION_CACHE_USER, CacheUser.class);
            }
        }
        return cacheUser;
    }

    /**
     * 获取不为空的用户信息缓存，为空时会查询用户信息并保存
     *
     * @return UserInfoDO
     */
    public CacheUser currentUserCacheNotNull() {
        CacheUser cacheUser = currentUserCache();
        if (cacheUser == null || cacheUser.getAccount() == null) {
            if (ObjectValidators.isEmpty(currentLoginUserCache())) {
                throw getAppException(MessageObject.CODE_NOT_LOGIN, "未登录，请登录后重试！");
            } else {
                throw getAppException(MessageObject.CODE_DENY_ACCESS, "权限不足，需要用户权限！");
            }
        }
        return cacheUser;
    }

    /**
     * 获取当前店铺登陆信息
     *
     * @return CacheStoreUser
     */
    public CacheStoreUser currentStoreUserCache() {
        CacheStoreUser cacheStoreUser;
        if (NO_LOGIN) {
            cacheStoreUser = new CacheStoreUser();
            cacheStoreUser.setAccount(20000);
            cacheStoreUser.setType(BusinessConstants.USER_TYPE_STORE);
            cacheStoreUser.setType("店铺管理员");
        } else {
            cacheStoreUser = getHttpSessionProxy()
                    .getAttribute(BusinessKeyConstants.SESSION_CACHE_STORE_USER, CacheStoreUser.class);
        }
        if (ObjectValidators.isEmpty(cacheStoreUser)) {
            UserDetailDO success = autoLoginByToken();
            if (ObjectValidators.isNotEmpty(success)) {
                cacheStoreUser = this.getHttpSessionProxy()
                        .getAttribute(BusinessKeyConstants.SESSION_CACHE_STORE_USER, CacheStoreUser.class);
            }
        }
        return cacheStoreUser;
    }

    /**
     * 获取当前店铺登陆信息，若获取失败则抛出异常，保证返回的信息不为空
     *
     * @return CacheStoreUser
     */
    public CacheStoreUser currentStoreUserCacheNotNull() {
        CacheStoreUser cacheStoreUser = currentStoreUserCache();
        if (cacheStoreUser == null || cacheStoreUser.getAccount() == null) {
            if (ObjectValidators.isEmpty(currentLoginUserCache())) {
                throw getAppException(MessageObject.CODE_NOT_LOGIN, "未登录，请登录后重试！");
            } else {
                throw getAppException(MessageObject.CODE_DENY_ACCESS, "权限不足，需要店铺权限！");
            }
        }
        return cacheStoreUser;
    }

    /**
     * 获取当前管理员登陆信息
     *
     * @return CacheAdminUser
     */
    public CacheAdminUser currentAdminUserCache() {
        CacheAdminUser cacheAdminUser;
        if (NO_LOGIN) {
            cacheAdminUser = new CacheAdminUser();
            cacheAdminUser.setAccount(30000);
            cacheAdminUser.setType(BusinessConstants.USER_TYPE_ADMIN);
            cacheAdminUser.setName("超级管理员");
        } else {
            cacheAdminUser = getHttpSessionProxy()
                    .getAttribute(BusinessKeyConstants.SESSION_CACHE_ADMIN_USER, CacheAdminUser.class);
        }
        if (ObjectValidators.isEmpty(cacheAdminUser)) {
            UserDetailDO success = autoLoginByToken();
            if (ObjectValidators.isNotEmpty(success)) {
                cacheAdminUser = this.getHttpSessionProxy()
                        .getAttribute(BusinessKeyConstants.SESSION_CACHE_ADMIN_USER, CacheAdminUser.class);
            }
        }
        return cacheAdminUser;
    }

    /**
     * 获取当前管理员登陆信息，若获取失败则抛出异常，保证返回的信息不为空
     *
     * @return CacheAdminUser
     */
    public CacheAdminUser currentAdminUserCacheNotNull() {
        CacheAdminUser cacheAdminUser = currentAdminUserCache();
        if (cacheAdminUser == null || cacheAdminUser.getAccount() == null) {
            if (ObjectValidators.isEmpty(currentLoginUserCache())) {
                throw getAppException(MessageObject.CODE_NOT_LOGIN, "未登录，请登录后重试！");
            } else {
                throw getAppException(MessageObject.CODE_DENY_ACCESS, "权限不足，需要管理员权限！");
            }
        }
        return cacheAdminUser;
    }

    /**
     * 获取当前登陆用户信息
     *
     * @return CacheLoginUser
     */
    public CacheLoginUser currentLoginUserCache() {
        CacheLoginUser cacheLoginUser;
        if (NO_LOGIN) {
            cacheLoginUser = new CacheLoginUser();
            cacheLoginUser.setAccount(10000);
            cacheLoginUser.setType(BusinessConstants.USER_TYPE_USER);
            cacheLoginUser.setName("李迅达");
            cacheLoginUser.setPassword("123123");
        } else {
            cacheLoginUser = getHttpSessionProxy()
                    .getAttribute(BusinessKeyConstants.SESSION_CACHE_LOGIN_USER, CacheLoginUser.class);
        }
        if (ObjectValidators.isEmpty(cacheLoginUser)) {
            UserDetailDO success = autoLoginByToken();
            if (ObjectValidators.isNotEmpty(success)) {
                cacheLoginUser = this.getHttpSessionProxy()
                        .getAttribute(BusinessKeyConstants.SESSION_CACHE_LOGIN_USER, CacheLoginUser.class);
            }
        }
        return cacheLoginUser;
    }

    /**
     * 获取当前登陆用户信息，若获取失败则抛出异常，保证返回的信息不为空
     *
     * @return CacheLoginUser
     */
    public CacheLoginUser currentLoginUserCacheNotNull() {
        CacheLoginUser cacheLoginUser = currentLoginUserCache();
        if (cacheLoginUser == null || cacheLoginUser.getAccount() == null) {
            throw getAppException(MessageObject.CODE_NOT_LOGIN, "未登录，请登录后重试！");
        }
        return cacheLoginUser;
    }

    /**
     * 抛出AppException异常，异常由全局异常捕获，返回MessageObject对象，默认code值为普通错误400
     *
     * @param code 状态码
     */
    public AppException getAppException(int code) {
        return new AppException(code);
    }

    /**
     * 抛出AppException异常，异常由全局异常捕获，返回MessageObject对象，默认code值为普通错误400
     *
     * @param msg 异常消息，将会作为消息返回给前端或者上级调用微服务
     */
    public AppException getAppException(String msg) {
        return new AppException(msg);
    }

    /**
     * 抛出AppException异常，异常由全局异常捕获，返回MessageObject对象，默认code值为普通错误400
     *
     * @param code 状态码
     * @param msg  异常消息，将会作为消息返回给前端或者上级调用微服务
     */
    public AppException getAppException(int code, String msg) {
        return new AppException(code, msg);
    }

    /**
     * 发送验证码，邮箱验证码或者短信验证码，自动保存到session中
     *
     * @param key             保存在session中的key,由调用方提供
     * @param action          验证码验证动作，如用户注册，用户登录
     * @param sendAuthCodeDTO 包含接收方的地址信息
     * @throws AppException 发送失败（参数条件错误或者发送错误等）抛出异常
     */
    public void sendAuthCode(String key, String action, SendAuthCodeDTO sendAuthCodeDTO) {
        //1. 验证是否超过一分钟
        CacheAuthCode cacheAuthCode = getHttpSessionProxy().getAttribute(key, CacheAuthCode.class);
        if (cacheAuthCode != null && cacheAuthCode.getTime() != null && cacheAuthCode.getTime()
                .plusSeconds(CODE_GAP).isAfter(LocalDateTime.now())) {
            // 没有超过一分钟，不能发送
            log.debug("没有超过一分钟，不能发送");
            throw getAppException("获取验证码过于频繁，请稍候再试");
        }
        if (BindingTypeDO.BINDING_TYPE_PHONE == sendAuthCodeDTO.getType()) {
            throw getAppException("短信注册维护中，请使用邮箱进行注册");
        }
        //2. 发送注册验证码
        String authCode = StringUtils.getAuthCode();
        //3. 使用模板填充数据
        switch (sendAuthCodeDTO.getType()) {
            case SendAuthCodeDTO.TYPE_EMAIL:
                EmailGeneralCodeDTO emailGeneralCodeDTO = new EmailGeneralCodeDTO();
                emailGeneralCodeDTO.setCode(authCode);
                emailGeneralCodeDTO.setTime(5);
                emailGeneralCodeDTO.setAction(action);
                emailGeneralCodeDTO.setEmail(sendAuthCodeDTO.getAccount());
                log.debug("即将发送邮箱验证码 {}", cacheAuthCode);
                cacheAuthCode = feignEmailAuthCode.sendGeneralCodeMessage(emailGeneralCodeDTO);
                log.debug("发送邮箱验证码成功 {}", cacheAuthCode);
                break;
            case SendAuthCodeDTO.TYPE_PHONE:
                throw new AppException("短信验证码需要企业验证，暂不支持短信验证码，请使用邮箱进行验证。");
            default:
                log.error("暂不支持的验证码发送方式");
        }
        //4. 保存
        log.debug("保存 {}", cacheAuthCode);
        getHttpSessionProxy().setAttribute(key, cacheAuthCode);
    }

    /**
     * 验证码用户上传的验证码是否正确
     *
     * @param key     验证码保存的key
     * @param code    用户上传的验证码
     * @param account 发送账号
     * @param type    账号类型
     * @throws AppException 验证失败
     */
    public void authSendCode(String key, String code, String account, int type) {
        CacheAuthCode cacheAuthCode = getHttpSessionProxy().getAttribute(key, CacheAuthCode.class);
        log.debug("获取到了验证码 {}", cacheAuthCode);
        if (cacheAuthCode == null || cacheAuthCode.getLateTime() == null || cacheAuthCode.timeIsLate()) {
            throw getAppException("验证码已过期，请重新获取");
        }
        if (cacheAuthCode.getAccounts() == null || !cacheAuthCode.getAccounts().get(0).equals(account)
                || !cacheAuthCode.getType().equals(type)) {
            throw getAppException("不是同一个注册账户");
        }
        if (!cacheAuthCode.getCode().equals(code)) {
            throw getAppException("验证码错误");
        }
        getHttpSessionProxy().removeAttribute(key);
    }

    /**
     * 常见一个图片验证码并将信息缓存到session中
     *
     * @return 图片验证码
     */
    public ImageCodeUtil.ImageCodeResult createImageCodeAndSave(String key) {
        if (ObjectValidators.isEmpty(key)) {
            throw getAppException("系统错误！请联系管理员修复！图片验证码缓存Key不能为空！");
        }
        ImageCodeUtil.ImageCodeResult result = imageCodeUtil.getImage();
        CacheImageCode cache = new CacheImageCode();
        cache.setLocalDateTime(result.getTime()).setText(result.getText());
        getHttpSessionProxy()
                .setAttribute(key, cache);
        return result;
    }

    /**
     * 验证图片验证码
     *
     * @param key 验证码缓存key
     * @param code 验证码
     */
    public void authImageCode(String key, String code) {
        if (ObjectValidators.isEmpty(key)) {
            throw getAppException("图片验证码缓存Key不能为空");
        }
        if (ObjectValidators.isEmpty(code)) {
            throw getAppException("图片验证码不能为空");
        }
        CacheImageCode cache = getHttpSessionProxy()
                .getAttribute(key, CacheImageCode.class);
        if (ObjectValidators.isEmpty(cache) || ObjectValidators.isEmpty(cache.getText())) {
            throw getAppException("获取验证码失败，请刷新图片验证码");
        }
        log.info("myCode {}  trueCode {}", code, cache.getText());
        if (!cache.getText().toLowerCase().equals(code.toLowerCase())) {
            throw getAppException("图片验证码错误");
        }
    }

    /**
     * 验证当前登陆用户的密码
     *
     * @param password 用户验证密码
     */
    public void authPassword(String password) {
        CacheLoginUser detail = currentLoginUserCacheNotNull();
        if (!detail.getPassword().equals(password)) {
            throw getAppException("密码错误");
        }
    }

    /**
     * 转换page对象
     *
     * @param page     分页后的page对象
     * @param function 转换函数
     * @param <C>      原对象数据类型
     * @param <R>      转换后的数据对象类型
     * @return Page<R>
     */
    public <C, R> Page<R> pageConvert(IPage<C> page, Function<C, R> function) {
        if (function == null) {
            throw getAppException("function 转换函数不能为空");
        }
        Page<R> resultPage = new Page<>();
        BeanUtils.copyProperties(page, resultPage);
        List<C> list = page.getRecords();
        List<R> resultList = new ArrayList<>(list.size());
        for (C t : list) {
            resultList.add(function.apply(t));
        }
        resultPage.setRecords(resultList);
        return resultPage;
    }

    /**
     * 根据url下载文件
     *
     * @param url      文件网络地址
     * @param fileName 下载文件名
     * @param request  HttpServletRequest
     * @return SpringMVC ResponseEntity
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public ResponseEntity<byte[]> downloadFileByUrl(String url, String fileName, HttpServletRequest request) {
        if (ObjectValidators.isEmpty(url)) {
            throw getAppException("url不能为空");
        }
        if (ObjectValidators.isEmpty(request)) {
            throw getAppException("系统错误，获取request失败");
        }
        try {
            URL ur = new URL(url);
            byte[] body;
            InputStream is = ur.openStream();
            body = new byte[is.available()];
            is.read(body);
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", "attchement;filename=" + fileName);
            HttpStatus statusCode = HttpStatus.OK;
            return new ResponseEntity<>(body, headers, statusCode);
        } catch (IOException e) {
            e.printStackTrace();
            throw getAppException("获取图片失败");
        }
    }

}
